home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / News / Alexandra.0.82 / Source / AMGErrorHandling.subproj / EMErrorManager.m < prev    next >
Encoding:
Text File  |  1996-01-30  |  9.9 KB  |  393 lines

  1.  
  2. #import "EMErrorManager.h"
  3. #import "EMErrorObserver.h"
  4. #import "EMErrorDescription.h"
  5. #import "EMObjcErrorCatcher.h"
  6. #import "localizable_strings.h"
  7. #import <appkit/appkit.h>
  8.  
  9. #define ALIGNMENT(type) (offsetof(struct { char c; type t; },t))
  10.  
  11. @implementation EMErrorManager
  12.  
  13. static id theEMErrorManager = nil;
  14.  
  15. //--------------------------------------------------------------------------------
  16. // HILFSFUNKTIONEN
  17. // Die ErrorReporter und -handler Funktionen, SignalHandler
  18. //--------------------------------------------------------------------------------
  19.  
  20. static void EMErrorReporter(NXHandler *errorState)
  21.     {
  22.     EMErrorInfo    *ex=(id)errorState->data1;
  23.  
  24.     NXLogError("EMErrorReporter: %s: #%d\n",[ex location],[ex code]);
  25.     }
  26.  
  27.  
  28. static void EMErrorHandler(NXHandler *errorState)
  29.     {
  30.     if(![[EMErrorManager new] handle:EMInfoObjectForHandler(errorState)])
  31.         NXDefaultTopLevelErrorHandler(errorState);
  32.     }
  33.  
  34.  
  35. static void EMSignalHandler(int signalno)
  36.     {
  37.     sigsetmask(0);  // unblock all signals...
  38.     EM_ERROR(EM_SIGBASE+signalno,NULL,NULL);
  39.     }
  40.  
  41.  
  42. //--------------------------------------------------------------------------------
  43. // HILFSFUNKTIONEN, Teil 2
  44. //--------------------------------------------------------------------------------
  45.  
  46. EMErrorInfo *EMInfoObjectForHandler(NXHandler *errorState)
  47.     {
  48.     EMErrorInfo                         *exception;
  49.     const struct { @defs(EMErrorInfo) }    *eip;
  50.  
  51.     if(errorState->data1!=NULL && (((int)(errorState->data1))%ALIGNMENT(id))==0 && 
  52.         ((eip=errorState->data1)->code==errorState->code))
  53.         exception=(id)errorState->data1;
  54.     else
  55.         exception=[[EMErrorInfo newWithCode:errorState->code 
  56.                 userInfo:errorState->data1:errorState->data2] getContext];
  57.     return exception;    
  58.     }
  59.  
  60. //    if(errorState->code>=NX_APP_ERROR_BASE && 
  61. //        errorState->code<NX_APP_ERROR_BASE+EM_ERROR_RANGE)
  62.  
  63. //--------------------------------------------------------------------------------
  64. // HILFSFUNKTIONEN, Teil 3
  65. //--------------------------------------------------------------------------------
  66.  
  67. /*
  68. static void EMFreeValues(void *val)
  69.     {
  70.     id    v=val;
  71.     
  72.     if([v isKindOf:[List class]])
  73.         [v freeObjects];
  74.     [v free];
  75.     }
  76. */
  77.  
  78. //--------------------------------------------------------------------------------
  79. // KLASSENMETHODEN
  80. // Sicherstellen, dass nur eine Instanz benutzt wird.
  81. //--------------------------------------------------------------------------------
  82.  
  83. + new
  84.     {
  85.     if(!theEMErrorManager)
  86.         {
  87.         NXZone *myZone=NXCreateZone(vm_page_size*4,vm_page_size*2,YES);
  88.  
  89.         NXNameZone(myZone,"EMErrorManager");
  90.         theEMErrorManager=self=[[super allocFromZone:myZone] init];
  91.         }
  92.     else 
  93.         self=theEMErrorManager;
  94.     return self;
  95.     }    
  96.  
  97.  
  98. //--------------------------------------------------------------------------------
  99. // INIT & FREE
  100. //--------------------------------------------------------------------------------
  101.  
  102. - init;
  103.     {
  104.     [super init];
  105.     [self readErrorDescriptions];
  106.     objectsToNotify=[[HashTable allocFromZone:[self zone]] 
  107.                             initKeyDesc:"i" valueDesc:"@"];
  108.     [EMObjcErrorCatcher setup];
  109.     [self installErrorReporter:YES];
  110.     [self installErrorHandler:YES];
  111.     [self installSignalHandler:YES];
  112.     return self;
  113.     }
  114.     
  115.  
  116. - free;
  117.     {
  118. //    [objectsToNotify freeKeys:NULL values:EMFreeValues];
  119. //  allgemeines Porblem: wann duerfen die EMErrorObserver freigegeben werden?
  120.     [objectsToNotify free];
  121.     return [super free];
  122.     }
  123.  
  124.  
  125. //--------------------------------------------------------------------------------
  126. // ERROR FILE
  127. //--------------------------------------------------------------------------------
  128.  
  129. - readErrorDescriptions;
  130.     {
  131.     return [self readErrorDescriptionsFromBundle:[NXBundle mainBundle]];
  132.     }
  133.  
  134.  
  135. - readErrorDescriptionsFromBundle:(NXBundle *)bundle;
  136.     {
  137.     char                path[MAXPATHLEN+1];
  138.     struct stat            buf;
  139.     NXTypedStream        *stream;
  140.     int                    vmajor,vemc;
  141.     HashTable            *newTable;
  142.     NXHashState          state;
  143.     const void          *key; 
  144.     EMErrorDescription    *ed;
  145.  
  146.     NX_DURING
  147.         [bundle getPath:path forResource:"Errors" ofType:"estore"];
  148.         if(strlen(path)<3)
  149.             NX_RAISE(NX_APP_ERROR_BASE,CANT_LOCATE_MSGS,NULL);
  150.         else if(stat(path,&buf))
  151.             NX_RAISE(NX_APP_ERROR_BASE,CANT_ACCESS_MSGS,NULL);
  152.         else if(!(buf.st_mode && S_IFREG))
  153.             NX_RAISE(NX_APP_ERROR_BASE,CANT_LOCATE_MSGS,NULL);
  154.         stream=NXOpenTypedStreamForFile(path,NX_READONLY);
  155.         NXSetTypedStreamZone(stream,[self zone]);
  156.         NXReadTypes(stream,"ii",&vmajor,&vemc);
  157.         if(vmajor*100+vemc > EM_MAJOR_VERSION*100+EM_EMC_VERSION)
  158.             NX_RAISE(NX_APP_ERROR_BASE,MSG_NEW_VERSION,NULL);
  159.         else if(vmajor*100+vemc < EM_MAJOR_VERSION*100+EM_EMC_VERSION)
  160.             NX_RAISE(NX_APP_ERROR_BASE,MSG_OLD_VERSION,NULL);
  161.         newTable=NXReadObject(stream);
  162.         NXCloseTypedStream(stream);
  163.         if(errorDescriptions==nil)
  164.             errorDescriptions=newTable;
  165.         else
  166.             {
  167.             state=[newTable initState];
  168.             while([newTable nextState:&state key:&key value:(void *)&ed]) 
  169.                 {
  170.                 if([errorDescriptions isKey:key])
  171.                     NX_RAISE(NX_APP_ERROR_BASE,ERROR_NUMBER_CLASH,NULL);
  172.                    [errorDescriptions insertKey:key value:ed];
  173.                 }
  174.             [newTable free];
  175.             }
  176.     NX_HANDLER
  177.         if([self errorDescriptionFor:EM_INTBASE+2])
  178.             EM_ERROR(EM_INTBASE+2,NXLocalHandler.data1,NULL);
  179.         else
  180.             { 
  181.             NXRunAlertPanel(INTERNAL_ERROR,CANT_LOAD_MESSAGES,QUIT_BUTTON,NULL,NULL,
  182.                         NXLocalHandler.data1,EM_MAJOR_VERSION,EM_EMC_VERSION);
  183.             exit(1);
  184.             }
  185.     NX_ENDHANDLER
  186.     
  187.     return self;
  188.     }
  189.  
  190.  
  191. - (HashTable *)errorDescriptions;
  192.     {
  193.     return errorDescriptions;
  194.     }
  195.     
  196.  
  197. - (EMErrorDescription *)errorDescriptionFor:(int)code;
  198.     {
  199.     return (EMErrorDescription *)[errorDescriptions valueForKey:(void *)code];
  200.     }
  201.  
  202.  
  203. //--------------------------------------------------------------------------------
  204. // Handler (de)installieren
  205. //--------------------------------------------------------------------------------
  206.  
  207. - installErrorReporter:(BOOL)flag;
  208.     {
  209.     if(flag)
  210.         NXRegisterErrorReporter(NX_APPBASE,NX_APPBASE+EM_ERROR_RANGE,
  211.                 EMErrorReporter);
  212.     else
  213.         NXRemoveErrorReporter(NX_APPBASE);
  214.     return self;
  215.     }
  216.  
  217.  
  218. - installErrorHandler:(BOOL)flag;
  219.     {
  220.     if(flag)
  221.         NXSetTopLevelErrorHandler(EMErrorHandler);
  222.     else
  223.         NXSetTopLevelErrorHandler(NXDefaultTopLevelErrorHandler);
  224.     return self;
  225.     }
  226.  
  227.  
  228. - installSignalHandler:(BOOL)flag;
  229.     {
  230.     BOOL     signals[]={1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,-1};
  231.     int        i;
  232.     void (*handler)(int);
  233.  
  234.     handler=flag?EMSignalHandler:SIG_DFL;
  235.     for (i=0;signals[i]!=-1;i++)
  236.         if(signals[i])  
  237.             signal(i,handler);
  238.     return self;
  239.     }
  240.  
  241.  
  242. //--------------------------------------------------------------------------------
  243. // Raise Error
  244. //--------------------------------------------------------------------------------
  245.  
  246. - raise:infoObject;
  247.     {
  248.     [infoObject getContext];
  249.     switch([[self errorDescriptionFor:[infoObject code]] severity])
  250.         {
  251.     case EMSeverityWarning: 
  252.         [self handle:infoObject];
  253.         break;
  254.     case EMSeverityError:
  255.         NX_RAISE([infoObject code],infoObject,NULL);
  256.         break;
  257.     case EMSeverityFatalError:
  258.         [self handle:infoObject];
  259.         exit(2);
  260.         break;
  261.     case EMSeverityUnknown:
  262.         if(([infoObject code])==EM_INTBASE+1)
  263.             {
  264.             NXRunAlertPanel(NULL,NO_UNKNOWN_EVEN,QUIT_BUTTON,NULL,NULL,
  265.                 [infoObject codeString]);
  266.             exit(2);
  267.             }
  268.         EM_ERROR(EM_INTBASE+1,(void *)[infoObject code],[infoObject location]);
  269.         break;
  270.         }
  271.     return self;
  272.     }
  273.  
  274. //--------------------------------------------------------------------------------
  275. // Fehler behandeln
  276. //--------------------------------------------------------------------------------
  277.  
  278. - handle:infoObject;
  279.     {
  280.     id    ed=[self errorDescriptionFor:[infoObject code]],
  281.         eo=[objectsToNotify valueForKey:(void *)[infoObject code]];
  282.  
  283.     [self notify:[ed actions] of:infoObject];
  284.     [self notify:eo of:infoObject];
  285.     [NXApp delayedFree:infoObject];
  286.     return ed;
  287.     }
  288.  
  289.  
  290. //--------------------------------------------------------------------------------
  291. // Objekte ueber den Fehler benachrichtigen
  292. //--------------------------------------------------------------------------------
  293.  
  294. - notify:obj of:infoObject;
  295.     {
  296.     if([obj isKindOf:[List class]])
  297.         [obj makeObjectsPerform:@selector(dispatch:) with:infoObject];
  298.     else
  299.         [obj perform:@selector(dispatch:) with:infoObject];
  300.     return self;
  301.     }
  302.     
  303.  
  304. //--------------------------------------------------------------------------------
  305. // Objekte registrieren, die im Fehlerfall benachrichrichtigt werden
  306. //--------------------------------------------------------------------------------
  307.  
  308. - addObserver:anObject selector:(SEL)aSel forError:(int)errorNumber;
  309.     {
  310.     return [self addObserver:anObject selector:aSel forErrors:errorNumber:1];
  311.     }
  312.     
  313.  
  314. - addObserver:anObject selector:(SEL)aSel forErrors:(int)base:(int)count;
  315.     {
  316.     id    observer,entry;
  317.     int    i;
  318.     
  319.     NX_DURING
  320.         observer=[EMErrorObserver allocFromZone:[self zone]];
  321.         [observer initWith:anObject andSelector:aSel];
  322.     NX_HANDLER
  323.         [observer free];
  324.         NX_RERAISE();
  325.     NX_ENDHANDLER
  326.     
  327.     for(i=base;i<base+count;i++)
  328.         {
  329.         entry=[objectsToNotify valueForKey:(void *)i];
  330.  
  331.         if(!entry)
  332.             [objectsToNotify insertKey:(void *)i value:observer];
  333.         else if(![entry isKindOf:[List class]])
  334.             [objectsToNotify insertKey:(void *)i
  335.                 value:[[[[List allocFromZone:[self zone]] 
  336.                                 init] addObject:entry] addObject:observer]];
  337.         else
  338.             [entry addObject:observer];
  339.         }
  340.     return self;
  341.     }
  342.     
  343.     
  344. - removeObserver:anObject forError:(int)errorNumber
  345.     {
  346.     return [self removeObserver:anObject forErrors:errorNumber:1];
  347.     }
  348.  
  349.  
  350. - removeObserver:anObject forErrors:(int)base:(int)count;
  351.     {
  352.     id    entry;
  353.     int    i,j;
  354.  
  355.     for(i=base;i<base+count;i++)
  356.         {
  357.         entry=[objectsToNotify valueForKey:(void *)i];
  358.     
  359.         if(!entry)
  360.             EM_ERROR(EM_INTBASE+12,(void *)i,NULL);
  361.         else if(![entry isKindOf:[List class]])
  362.             if([entry observer]==anObject)
  363.                 [objectsToNotify removeKey:(void *)i];
  364.             else
  365.                 EM_ERROR(EM_INTBASE+12,(void *)i,NULL);
  366.         else     
  367.             {
  368.             for(j=[entry count]-1;j>=0;j--)
  369.                 if([[entry objectAt:j] observer]==anObject)
  370.                     break;
  371.             if(j>=0)
  372.                 {
  373.                 [entry removeObjectAt:j];
  374.                 if([entry count]<2)
  375.                     {
  376.                     [objectsToNotify insertKey:(void *)i value:[entry lastObject]];
  377.                     [entry free];
  378.                     }
  379.                 }
  380.             else
  381.                 EM_ERROR(EM_INTBASE+12,(void *)i,NULL);
  382.             }
  383.         }
  384.     return self;
  385.     }
  386.     
  387.  
  388. //--------------------------------------------------------------------------------
  389. // THAT'S IT
  390. //--------------------------------------------------------------------------------
  391.  
  392. @end
  393.